const fs = require("fs");
const glob = require("glob");
const axios = require("axios");
const https = require("https");

const targetPath = process.argv[2];

if (!fs.existsSync(targetPath) || !fs.lstatSync(targetPath).isDirectory()) {
  console.error("must provide a directory path");
  process.exit(1);
}

console.log("[tiny] compression initiated");

const TINYPNG_HEADERS = {
  rejectUnauthorized: false,
  "Postman-Token": Date.now(),
  "Cache-Control": "no-cache",
  "Content-Type": "application/x-www-form-urlencoded",
  "User-Agent":
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
};

function getRandomIP() {
  return Array.from(Array(4))
    .map(() => parseInt(Math.random() * 255))
    .join(".");
}

function getImageFiles(input) {
  return new Promise((resolve, reject) => {
    glob(
      "**/*.{png,jpg,jpeg}",
      {
        cwd: input,
      },
      (err, files) => {
        if (err) {
          return reject(err);
        }
        resolve(files.map((file) => `${input}/${file}`));
      }
    );
  });
}

function uploadImage(img) {
  return new Promise((resolve, reject) => {
    const req = https.request(
      {
        method: "POST",
        hostname: "tinypng.com",
        path: "/web/shrink",
        headers: Object.assign(
          {
            "X-Forwarded-For": getRandomIP(),
          },
          TINYPNG_HEADERS
        ),
      },
      function (res) {
        res.on("data", (buf) => {
          resolve(JSON.parse(buf.toString()));
        });
      }
    );
    req.write(fs.readFileSync(img), "binary");
    req.on("error", (e) => {
      reject(e);
    });
    req.end();
  });
}

async function tiny(filePath) {
  const data = await uploadImage(filePath);

  if (data.error) {
    console.log(`${filePath} fail: ${data.message}`);
  } else if (data.output.url) {
    const res = await axios({
      url: data.output.url,
      method: "get",
      headers: Object.assign(
        {
          "X-Forwarded-For": getRandomIP(),
        },
        TINYPNG_HEADERS
      ),
      responseType: "stream",
    });

    res.data.pipe(fs.createWriteStream(filePath));

    console.log(
      `${filePath} success: ratio=(${data.output.size}/${data.input.size})=${data.output.ratio}`
    );
  }
}

async function run(input) {
  const imageFiles = await getImageFiles(input);

  const promises = [];

  for (const image of imageFiles) {
    promises.push(tiny(image));
  }

  return Promise.all(promises);
}

run(targetPath).then(() => {
  console.log("[tiny] compression completed");
});
